微前端的概念与起源
微前端(Micro Frontends)是一种通过将前端应用程序拆分成小型、独立的功能单元来构建复杂用户界面的技术架构模式。其核心思想与微服务一脉相承 -- 把前端应用拆分成多个独立的子应用,每个子应用可以独立开发、测试、维护和部署,最终像拼图一样组合成一个完整的应用。
微前端要解决的核心问题类似于 iframe,但比 iframe 更优雅。iframe 虽然能实现应用嵌入,但存在几个致命缺陷:
- 用户体验差 -- iframe 的加载、滚动、弹窗等行为与主应用不一致
- 跨域问题 -- 不同源的 iframe 通信受限
- 状态管理困难 -- iframe 内外的数据共享和状态同步非常复杂
- 技术栈隔离 -- 无法在同一个页面中整合不同框架(Angular、Vue、React)
微前端框架的出现正是为了在解决这些问题的同时,让不同技术栈的前端应用能够在同一个页面中协同工作。
微前端的核心挑战
微前端场景下存在几个核心问题:样式冲突、消息通信、脚本互斥、公共依赖加载。微前端框架正是因这些问题应运而生。
应用隔离
主应用与微应用之间、微应用与微应用之间都需要做两种隔离:
- JS 隔离(沙箱) -- 防止子应用的全局变量污染主应用和其他子应用
- CSS 隔离 -- 防止子应用的样式影响主应用和其他子应用
CSS 样式隔离
在微前端场景下,不同技术栈的子应用会被集成到同一个运行时中,必须在框架层确保各子应用之间不会出现样式互相干扰。例如:一个团队的微应用样式表为 h2 { color: black; },而另一个团队的为 h2 { color: blue; },这两个选择器附加在同一页面上就会冲突。
常见的 CSS 隔离方案:
- 严格的命名约定(如 BEM)
- CSS Module
- CSS-in-JS 库
- Shadow DOM
Javascript 沙箱隔离
每当微应用的 JavaScript 被加载并运行时,它的核心实际上是对全局对象 Window 的修改以及一些全局事件的改变。例如 jQuery 运行后会在 Window 上挂载 window.$,React 和 Vue 也不例外。
因此,需要在加载和卸载每个微应用的同时消除这种冲突和影响,最普遍的做法是采用沙箱机制(SandBox)。常见实现方式:
- 沙箱快照 -- 在微应用加载前保存 Window 快照,卸载后恢复
- ES6 Proxy 代理 -- 通过 Proxy 拦截对 Window 的读写操作
跨应用通信
微前端中最常见的问题之一就是如何让微应用之间相互通信。一般建议让微应用之间尽可能少地交流,因为这会重新引入不适当的耦合。通常只需要某种程度的跨应用通信即可。
| 通信方式 | 原理 | 适用场景 |
|---|---|---|
| URL 参数 | 通过地址栏传递数据 | 简单的状态传递 |
| 发布订阅(pub/sub) | 自定义事件总线 | 松耦合的组件通信 |
| 全局 State Store | 共享的状态管理 | 需要全局共享状态的场景 |
| postMessage | 浏览器原生 API | 跨 iframe 通信 |
| CustomEvent | 浏览器原生事件 | 轻量级事件通知 |
微前端的应用场景
典型场景:新旧系统整合
假设公司有一个正在运行的 Vue 2 项目,现在需要把一个新开发的 React 项目的部分页面整合进来。如果两个系统之间不需要鉴权,直接用 iframe 嵌入即可。但一旦涉及到鉴权跳转和状态通信,iframe 就力不从心了,这时候微前端框架就能发挥价值。
典型场景:多框架共存
一个页面上同时存在 Angular、React 和 Vue(甚至不同版本的 Vue),这种场景只能通过微前端框架来实现。
注意事项
微前端是一种过渡方案,不是长久之计。长期来看,应该逐步将旧系统重构或改造为统一的前端框架,这样性能最好、开发效率最高。微前端的价值在于平滑过渡,避免一次性重写带来的巨大风险。
主流微前端框架对比
single-spa
Single-spa 是最早的微前端框架,兼容多种前端技术栈。它是一个将多个单页面应用聚合为一个整体应用的 JavaScript 微前端框架。
工作原理:single-spa 是一个顶层路由,当路由处于活动状态时,它会下载并执行该路由对应的代码。它不依赖于单个框架,你可以在不同的新框架中随意使用,最终用一个公共的路由实现完美切换。
| 维度 | 评价 |
|---|---|
| 优点 | 敏捷性高、独立开发部署、技术栈无关、支持增量升级、维护和 bugfix 简单 |
| 缺点 | 无通信机制、不支持 JS 沙箱、存在样式冲突、不支持预加载 |
| 适用 | 对沙箱要求不高的简单场景 |
正是因为有了 single-spa,才让大部分微前端框架得以出现,以下框架几乎都拥有 single-spa 的优点。
qiankun(乾坤)
qiankun 是一个基于 single-spa 的、阿里系开源的微前端框架,旨在帮助大家更简单、无痛地构建一个生产可用的微前端架构系统。是目前国内使用最广泛的方案。
设计理念:
- 主应用微应用都能做到技术栈无关,qiankun 对于用户而言只是一个类似 jQuery 的库,调用几个 API 即可完成微前端改造
- HTML entry 及沙箱的设计,使得微应用的接入像使用 iframe 一样简单
- 核心目标是将巨石应用拆解成若干可以自治的松耦合微应用,确保微应用真正具备独立开发、独立运行的能力
| 维度 | 评价 |
|---|---|
| 优点 | 基于 single-spa 封装开箱即用、技术栈无关、HTML Entry 接入方式、样式隔离、JS 沙箱、资源预加载、umi 插件、社区活跃 |
| 缺点 | 对老旧项目(jQuery 等)支持不够友好,eval 的使用存在安全和性能争议 |
| 适用 | 大多数企业级项目首选 |
另外阿里系还有 Icestark(面向大型系统的微前端解决方案)和 Alibaba Cloud Alfa(阿里云控制台孵化的企业级微前端方案),但社区活跃度和 demo 较少,了解即可。
micro-app
micro-app 是京东零售推出的微前端框架,基于 Web Component 原生组件进行渲染,从组件化的思维实现微前端,旨在降低上手难度、提升工作效率。
它是目前市面上接入微前端成本最低的框架,提供了 JS 沙箱、样式隔离、元素隔离、预加载、资源地址补全、插件系统、数据通信等完善的功能。
| 维度 | 评价 |
|---|---|
| 优点 | 使用简单(一行代码接入)、功能强大、兼容所有主流框架、JS 沙箱、样式隔离、qiankun 的优势它都有 |
| 缺点 | 仍处于 RC 阶段(尚未正式发布),案例相对较少 |
| 适用 | 对 Web Component 有偏好的团队 |
EMP
EMP 是欢聚时代基于 Webpack 5 Module Federation 搭建的微前端方案。
| 维度 | 评价 |
|---|---|
| 优点 | 依赖自动管理(可共享 Host 依赖,版本不满足时自动 fallback)、共享模块粒度自由掌控、共享模块可通过异步加载调用 |
| 缺点 | 无法做到多框架兼容、需要统一 Webpack 5 技术栈、文档和社区不够活跃 |
| 适用 | 技术栈统一且使用 Webpack 5 的团队 |
Garfish
Garfish 是字节跳动开源的微前端解决方案,经过大量线上应用打磨和测试,功能稳定可靠。参考了 qiankun 的设计思想,并在此基础上做了调整和扩展。
| 维度 | 评价 |
|---|---|
| 优点 | 支持依赖共享(极大降低包体积,减少重复加载)、多实例运行、强大预加载能力、内置数据收集、高度可扩展的插件机制 |
| 缺点 | 社区相对较小 |
| 适用 | 对包体积和依赖共享有要求的场景 |
其他值得了解的框架
| 框架 | 来源 | 特点 |
|---|---|---|
| Bit | 国外 bit 团队 | 跨项目的组件复用平台,适合技术栈统一的项目 |
| Luigi | SAP 团队 | 面向未来、技术栈无关、提供一致的用户导航 |
| OC (OpenComponent) | 开源 | "前端世界中的无服务器",包含从组件到注册表、模板、CLI 的完整体系 |
| Piral | smapiot 团队 | 基于 React,高度模块化,国外社区较好的选择 |
框架选择建议
按场景选择
| 项目场景 | 推荐框架 |
|---|---|
| 后台管理系统(最新 MV* 框架) | Qiankun、Micro App、Garfish、Luigi、Piral |
| 需要聚合老旧框架(jQuery) | Micro App(优先)、Qiankun |
| 需要 SEO | Piral、PuzzleJs |
| 依赖共享和包体积优化 | Garfish |
按综合排序
根据稳定性、功能完善度和社区活跃度:
- qiankun -- 首选,文档最全、社区最活跃、issues 解决速度快
- Garfish -- 推荐尝试,依赖共享是一大亮点
- micro-app -- 可以尝试,但需关注其正式版发布进度
- single-spa -- 适合对沙箱和隔离要求不高的简单场景
选择框架时重点考察:
- 官方更新频率和版本迭代速度
- GitHub issues 的响应和解决速度
- JS 沙箱、CSS 隔离等基础特性的实现质量
- 社区活跃度和可用案例数量
↑